#include "net_connection.hpp"
#include "../shared/network.hpp"
#include "ClientPlayer.hpp"
#include <SFML/Network.hpp>

#include <iostream>
#include <vector>
using namespace std;

sf::Socket::Status Net_Connection::SockSend(sf::Packet& Packet)
{
    return this->Sock.Send(Packet,this->Ip,this->Port);
}

sf::Socket::Status Net_Connection::SockRecv(sf::Packet& Packet)
{
    sf::IPAddress dummy1;
    sf::Uint16 dummy2;

    return this->Sock.Receive(Packet,dummy1,dummy2);
}

void Net_Connection::RemoveFromVector(sf::Int32 pid)
{
    for(vector<class ClientPlayer>::iterator iter = this->clients.begin(); iter != this->clients.end(); ++iter)
    {
        if(iter->GetPid() == pid)
        {
            this->clients.erase(iter);
            return;
        }
    }
    throw "No such client";
}

ClientPlayer& Net_Connection::GetClientPlayerByPid(sf::Int32 pid)
{
    for(vector<class ClientPlayer>::iterator iter = this->clients.begin(); iter != this->clients.end(); ++iter)
    {
        if(iter->GetPid() == pid)
        {
            return *iter;
        }
    }
    throw "No such client";
}

void Net_Connection::disconnect()
{
    sf::Packet p = PK_CLT_DISCONNECT();
    this->SockSend(p);
}

void Net_Connection::connect(sf::IPAddress& Ip, sf::Uint16& port)
{
    this->Ip = Ip;
    this->Port = port;
    this->Sock.Bind(31337);
    sf::Packet p = PK_CLT_CONNECT();
    this->SockSend(p);

    sf::Packet Packet;
    if(this->SockRecv(Packet) == sf::Socket::Done)
    {
        sf::Uint8 type = Packet_Type(Packet);
        if(type == PKTYPE_SRV_PLCONNECT)
        {
            this->pid = PK_SRV_PLCONNECT(Packet).pid;
            cout << "Our Pid is " << this->pid << endl;
        }
    }
    this->Sock.SetBlocking(false);
    this->pos = sf::Vector2f(0,0);
    this->angle = 0;
}

void Net_Connection::move(float x, float y)
{
    if(x != 0.f || y != 0.f)
    {
        sf::Packet Packet = PK_CLT_PLMOVE(x,y,0.f);
        this->SockSend(Packet);
    }
}

void Net_Connection::rotate(float angle)
{
    if(angle != 0)
    {
        sf::Packet Packet = PK_CLT_PLMOVE(0.f,0.f,angle);
        this->SockSend(Packet);
    }
}

void Net_Connection::receive()
{
    sf::Packet Packet;
    if(this->SockRecv(Packet) == sf::Socket::Done)
    {
        sf::Uint8 type = Packet_Type(Packet);
        if(type == PKTYPE_SRV_PLCONNECT)
        {
            struct PKCONTENT_SRV_PLCONNECT pkcontent = PK_SRV_PLCONNECT(Packet);

            ClientPlayer client;
            client.SetPid(pkcontent.pid);
            client.SetPosition(sf::Vector2f(0,0));
            client.SetRotation(0);
            this->clients.push_back(client);

            cout << "Client connected with PID " << pkcontent.pid << endl;
            return;
        }

        if(type == PKTYPE_SRV_PLDISCONNECT)
        {
            struct PKCONTENT_SRV_PLDISCONNECT pkcontent = PK_SRV_PLDISCONNECT(Packet);
            this->RemoveFromVector(pkcontent.pid);

            cout << "Client disconnected with PID " << pkcontent.pid << endl;
            return;
        }

        if(type == PKTYPE_SRV_PLPOS)
        {
            struct PKCONTENT_SRV_PLPOS pkcontent = PK_SRV_PLPOS(Packet);
            if(pkcontent.pid == this->pid)
            {
                this->pos = sf::Vector2f(pkcontent.x,pkcontent.y);
                this->angle = pkcontent.rotation;
                cout << "Updating own position (" << pkcontent.x << "," << pkcontent.y << ", " << pkcontent.rotation << ")" << endl;
            }
            else
            {
                ClientPlayer& client = this->GetClientPlayerByPid(pkcontent.pid);
                client.SetPosition(sf::Vector2f(pkcontent.x,pkcontent.y));
                client.SetRotation(pkcontent.rotation);
                cout << "Updating client " << pkcontent.pid << " (" << pkcontent.x << "," << pkcontent.y << ", " << pkcontent.rotation << ")" << endl;
            }
            return;
        }
    }
}

vector<class ClientPlayer> Net_Connection::GetClients()
{
    return this->clients;
}

sf::Int32 Net_Connection::GetPid()
{
    return this->pid;
}

sf::Vector2f Net_Connection::GetPosition()
{
    return this->pos;
}

float Net_Connection::GetRotation()
{
    return this->angle;
}
